
const isArray = (obj) => {
  return Object.prototype.toString.call(obj) === '[object Array]'
}

const isString = (obj) => {
  return Object.prototype.toString.call(obj) === '[object String]'
}

class BaseOpt { // interface
  caculate() {}
}

class EqualOpt extends BaseOpt {
  static name = 'equal'

  caculate(left, right) {
    // TODO: 包含整形比较，后期要严格控制类型
    return left == right
  }
}

class NotEqualOpt extends BaseOpt {
  static name = 'notEqual'

  caculate(left, right) {
    // TODO: 包含整形比较，后期要严格控制类型
    return left != right
  }
}

class LargerOpt extends BaseOpt {
  static name = 'larger'
  caculate(left, right) {
    return left > right
  }
}

class LargerEqualOpt extends BaseOpt {
  static name = 'largerEqual'
  caculate(left, right) {
    return left >= right
  }
}

class SmallerOpt extends BaseOpt {
  static name = 'smaller'
  caculate(left, right) {
    return left < right
  }
}

class SmallerEqualOpt extends BaseOpt {
  static name = 'smallerEqual'
  caculate(left, right) {
    return left <= right
  }
}

// 全部选项在用户已选列表中，才可以满足
class ContainOpt extends BaseOpt {
  static name = 'contain'
  caculate(left, right) {
    if (isString(left) && isArray(right)) {
      left = left.split(',')
      for (let i = 0; i < right.length; i++) {
        if (left.indexOf(right[i]) === -1) {
          return false
        }
      }

      return true
    }

    return false
  }
}

// 全部选项都不在用户已选列表中，才满足
class NotContainOpt extends BaseOpt {
  static name = 'notContain'
  caculate(left, right) {
    if (isString(left) && isArray(right)) {
      left = left.split(',')
      for (let i = 0; i < right.length; i++) {
        if (left.indexOf(right[i]) > -1) {
          return false
        }
      }

      return true
    }

    return true
  }
}

class NullOpt extends BaseOpt {
  static name = 'null'
  caculate(left) {
    return left === ''
  }
}

class NotNullOpt extends BaseOpt {
  static name = 'notNull'
  caculate(left) {
    return left !== ''
  }
}

class NoneOpt extends BaseOpt {
  static name = 'none'
  caculate() {
    return false
  }
}

const optMap = [
  EqualOpt, NotEqualOpt, LargerOpt, LargerEqualOpt, SmallerOpt, SmallerEqualOpt,
  ContainOpt, NotContainOpt, NullOpt, NotNullOpt, NoneOpt,
].reduce((ret, item) => ({
  ...ret,
  [item.name]: new item()
}), {})

export const getOpt = (name) => {
  return optMap[name] || optMap['none']
}
